package com.into.common.csv.engine;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.beanutils.PropertyUtils;

import com.csvreader.CsvReader;
import com.into.common.csv.*;

public class CSVParser {
	protected static final char	DEFAULT_DELIMITER	= ';';
	protected char							delimiter					= DEFAULT_DELIMITER;
	protected int								skipLines					= 0;

	public CSVParser() {
	}

	public CSVParser(char delimiter) {
		this.delimiter = delimiter;
	}

	public CSVParser(char delimiter, int skipLines) {
		this.delimiter = delimiter;
		this.skipLines = skipLines;
	}

	public List<? extends Object> fromCSV(
			CSVFieldsDefiner fieldsDefiner, String csvFile) throws Exception {
		CsvReader reader = new CsvReader(csvFile, delimiter);
		List<Object> toReturn = new ArrayList<Object>();
		skipLines(reader);
		while (reader.readRecord()) {
			Object instance = fromCSV(fieldsDefiner, reader.getValues());
			toReturn.add(instance);
		}
		return toReturn;
	}

	private void skipLines(CsvReader reader) throws IOException {
		for (int i = 0; i < skipLines; i++) {
			reader.readRecord();
		}
	}

	protected Object fromCSV(CSVFieldsDefiner fieldsDefiner,
			String[] values) throws Exception {
		Object toReturn = fieldsDefiner.createInstance(values);
		if (toReturn == null)
			throw new UnsupportedOperationException("No class to read \n\t"
					+ Arrays.asList(values));

		CSVField<?>[] fields = fieldsDefiner.getCSVFields(values);
		if (values.length == 0)
			return null;

		// if (values.length < fields.length)
		// throw new IllegalArgumentException("Line : \n\t" + Arrays.asList(values)
		// + " not compatible with (smaller than) object " + toReturn
		// + "'s fields : \n\t" + Arrays.asList(fields));

		for (int i = 0; i < fields.length; i++) {
			CSVField<?> field = fields[i];
			CSVConverter<?> converter = field.getConverter();
			try {
				if (field.isOnlyCSV()) {
					assert converter instanceof CSVOnlyValueConverter : "Field "
							+ field.getName()
							+ " is a csvonly field, it must have a converter either null or instance of "
							+ CSVOnlyValueConverter.class;
					if (converter != null) {
						((CSVOnlyValueConverter<?>) converter).setFromString(values[i],
								toReturn, field);
					}
					continue;
				}

				Object convertedValue = values[i];
				if (converter != null)
					convertedValue = converter.fromString(values[i]);

				PropertyUtils.setProperty(toReturn, field.getName(), convertedValue);
			} catch (Exception ex) {
				throw new RuntimeException("Error on field :" + field + ", on type : "
						+ toReturn.getClass().getSimpleName() + " on ref : " + values[1]
						+ "\n", ex);
			}
		}

		return toReturn;
	}
}
